﻿#include "FITKGraphObjectGeoInstance.h"

// VTK
#include <vtkTransform.h>
#include <vtkTransformFilter.h>
#include <vtkUnstructuredGrid.h>
#include <vtkPolyData.h>

// Graph 
#include "FITKGraphCommons.h"
#include "FITKPartDataSetManager.h"
#include "FITKGraphObjectModelHighlighting.h"
#include "FITK_Interface/FITKVTKAlgorithm/FITKGraphActor.h"

// Data
#include "FITK_Component/FITKAbaqusData/FITKAbaqusPart.h"
#include "FITK_Interface/FITKInterfaceModel/FITKAssInstance.h"

namespace Exchange
{
    FITKGraphObjectGeoInstance::FITKGraphObjectGeoInstance(AbaqusData::FITKDataCase* caseData, Interface::FITKAbstractAssInstance* instance)
        : FITKGraphObjectGeoModelBase(caseData, instance)
    {
        if (!instance)
        {
            return;
        }

        // Initialize.
        init();

        // Generate the shape data and actors.
        generateGraph();

        // Save the data type.
        m_graphInfo.Type = GraphDataType::GeometryInstanceGraph;
        m_graphInfo.InstanceId = instance->getDataObjectID();
    }

    FITKGraphObjectGeoInstance::~FITKGraphObjectGeoInstance()
    {
        // Delete vtk objects.
        deleteVtkObj(m_transform);
        deleteVtkObj(m_transformFilterFace);
        deleteVtkObj(m_transformFilterEdge);
        deleteVtkObj(m_transformFilterPoint);
    }

    void FITKGraphObjectGeoInstance::init()
    {
        this->Superclass::init();

        // Create and initialize the instance.
        m_transform = vtkTransform::New();       

        // Get the transform matrix from instance.
        Interface::FITKAbstractAssInstance* instance = dynamic_cast<Interface::FITKAbstractAssInstance*>(_dataObj);
        if (instance)
        {
            FITKGraphCommons::GetInstanceTransform(instance, m_transform);
        }

        AbaqusData::FITKAbaqusPart* part = dynamic_cast<AbaqusData::FITKAbaqusPart*>(instance->getModel());
        if (!part)
        {
            return;
        }

        PartGeomDataVTK* data{ nullptr };
        bool flag = FITKPartDataSetManager::getInstance()->getPartGeomData(part->getDataObjectID(), data);
        if (!flag)
        {
            return;
        }

        // Create the transform filter.     
        m_transformFilterPoint = vtkTransformFilter::New();
        m_transformFilterEdge = vtkTransformFilter::New();
        m_transformFilterFace = vtkTransformFilter::New();
        
        m_transformFilterPoint->SetTransform(m_transform);
        m_transformFilterEdge->SetTransform(m_transform);
        m_transformFilterFace->SetTransform(m_transform);

        // Initialize the input data object.
        m_transformFilterPoint->SetInputData(data->DataSetVertex);
        m_transformFilterEdge->SetInputData(data->DataSetEdge);
        m_transformFilterFace->SetInputData(data->DataSetFace);

        // Initialize the highlightor.
        m_graphObjHighlight->setModelInputConnection(m_transformFilterEdge->GetOutputPort());
        m_graphObjPreHighlight->setModelInputConnection(m_transformFilterEdge->GetOutputPort());

        // Get the part id.
        if (!instance)
        {
            return;
        }

        m_graphInfo.PartId = part->getDataObjectID();
    }

    void FITKGraphObjectGeoInstance::update(bool forceUpdate)
    {
        // Update the geometry data.
        this->Superclass::update(forceUpdate);

        // Update the transform.
        Interface::FITKAbstractAssInstance* instance = dynamic_cast<Interface::FITKAbstractAssInstance*>(_dataObj);
        if (instance)
        {
            FITKGraphCommons::GetInstanceTransform(instance, m_transform);
        }

        // Update pipelines.
        if (!m_fActorFace || !m_fActorEdge || !m_fActorVertex)
        {
            return;
        }

        m_fActorVertex->update();
        m_fActorEdge->update();
        m_fActorFace->update();
    }

    AbaqusData::FITKAbaqusPart* FITKGraphObjectGeoInstance::getPartData()
    {
        // Get the part data.
        Interface::FITKAbstractAssInstance* instance = dynamic_cast<Interface::FITKAbstractAssInstance*>(_dataObj);
        if (!instance)
        {
            return nullptr;
        }

        AbaqusData::FITKAbaqusPart* part = dynamic_cast<AbaqusData::FITKAbaqusPart*>(instance->getModel());
        return part;
    }

    void FITKGraphObjectGeoInstance::generateGraph()
    {
        // Create the actors.
        this->Superclass::generateGraph();

        if (!m_fActorFace || !m_fActorEdge || !m_fActorVertex)
        {
            return;
        }

        m_fActorVertex->setInputConnection(m_transformFilterPoint->GetOutputPort());
        m_fActorEdge->setInputConnection(m_transformFilterEdge->GetOutputPort());
        m_fActorFace->setInputConnection(m_transformFilterFace->GetOutputPort());

        // Set face color.
        m_fActorFace->setColor(FITKGraphCommons::s_geometryInstanceColor);
    }

    void FITKGraphObjectGeoInstance::colorByDefault(bool forceUpdate)
    {
        Q_UNUSED(forceUpdate);

        if (!m_fActorFace)
        {
            return;
        }

        // Set face color.
        m_fActorFace->setColor(FITKGraphCommons::s_geometryInstanceColor);

        // Save the status.
        m_colorMode = ColorMode::ColorDefault;
    }
}   // namespace Exchange